import axios from 'axios';
import { Message, MessageBox, Notification } from 'element-ui';
import store from '@/store';
import { getAccessToken, getRefreshToken, setToken } from '@/utils/auth';
import errorCode from '@/utils/errorCode';
import { refreshToken } from '@/api/login';
import route from '../router/index';

// 需要忽略的提示。忽略后，自动 Promise.reject('error')
const ignoreMsgs = [
	'无效的刷新令牌', // 刷新令牌被删除时，不用提示
	'刷新令牌已过期' // 使用刷新令牌，刷新获取新的访问令牌时，结果因为过期失败，此时需要忽略。否则，会导致继续 401，无法跳转到登出界面
];

// 是否显示重新登录
export const isRelogin = { show: false };
// Axios 无感知刷新令牌，参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
// 请求队列
let requestList = [];
// 是否正在刷新中
let isRefreshToken = false;
let refreshCount = 0;
const baseUrl = process.env.VUE_APP_BASE_API;

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
const service = axios.create({
	baseURL: baseUrl,
	timeout: 60000, // 超时限制为一分钟
	withCredentials: false
});
// request拦截器
service.interceptors.request.use(config => {
	config.headers['service-name'] = 'spin';
	config.headers['request-environment'] = process.env.VUE_APP_REQUEST_ENV;

	// 针对产量分段接口的特殊处理,遇到接口路径包含有api-segment的，将baseUrl的api替换为api-segment
	const spiSign = 'api-segment';
	if (config.url.indexOf(spiSign) !== -1) {
		config.baseURL = config.baseURL + '-segment/';
		config.url = config.url.substring(config.url.indexOf(spiSign) + spiSign.length);
	}

	config.headers['tenant-id'] = getPlatformCustomerId() || '';
	const isToken = (config.headers || {}).isToken === false;
	if (getAccessToken() && !isToken) {
		config.headers['Authorization'] = 'Bearer ' + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
	}
	// get请求映射params参数
	if (config.method === 'get' && config.params) {
		let url = config.url + '?';
		for (const propName of Object.keys(config.params)) {
			const value = config.params[propName];
			const part = encodeURIComponent(propName) + '=';
			if (value !== null && typeof (value) !== 'undefined') {
				if (typeof value === 'object') {
					for (const key of Object.keys(value)) {
						const params = propName + '[' + key + ']';
						const subPart = encodeURIComponent(params) + '=';
						url += subPart + encodeURIComponent(value[key]) + '&';
					}
				} else {
					url += part + encodeURIComponent(value) + '&';
				}
			}
		}
		url = url.slice(0, -1);
		config.params = {};
		config.url = url;
	}
	return config;
}, error => {
	Promise.reject(error);
});
// 响应拦截器
service.interceptors.response.use(async res => {
		// 重置刷新token的次数
		if (res.request.responseURL.indexOf('system/auth/refresh-token') === -1) {
			if (res.data.status === 200) {
				refreshCount = 0;
			}
		}
		// 未设置状态码则默认成功状态
		const code = res.data.status || 200;
		// 获取错误信息
		const msg = res.data.message || errorCode[code] || errorCode['default'];
		if (code !== 200) {
			if (msg === '无效的刷新令牌') { // hard coding：忽略这个提示，直接登出
			} else if (code === 202) {
				return res;
			} else if (ignoreMsgs.indexOf(msg) !== -1) { // 如果是忽略的错误码，直接返回 msg 异常
				return Promise.reject(msg);
			} else if (code === 401) {
				// 如果未认证，并且未进行刷新令牌，说明可能是访问令牌过期了
				if (!isRefreshToken) {
					isRefreshToken = true;
					// 1. 如果获取不到刷新令牌，则只能执行登出操作
					if (!getRefreshToken()) {
						return handleAuthorized();
					}
					// 刷新成功超过4次，新的token依然响应无效时，停止刷新（主要用于解决测试环境内部分页面访问的是生产环境的数据，导致不断循环刷新token的情况）
					if (refreshCount >= 4) {
						requestList.forEach(cb => cb());
						// 提示是否要登出。即不回放当前请求！不然会形成递归
						return handleAuthorized();
						// return new Promise((resolve, reject) => reject());
					}
					// 2. 进行刷新访问令牌
					try {
						const refreshTokenRes = await refreshToken();
						refreshCount++;
						// 2.1 刷新成功，则回放队列的请求 + 当前请求
						setToken(refreshTokenRes.data.res);
						// setToken(refreshTokenRes.data.res.accessToken);
						requestList.forEach(cb => cb());
						return service(res.config);
					} catch (e) { // 为什么需要 catch 异常呢？刷新失败时，请求因为 Promise.reject 触发异常。
						// 2.2 刷新失败，只回放队列的请求
						requestList.forEach(cb => cb());
						// 提示是否要登出。即不回放当前请求！不然会形成递归
						return handleAuthorized();
					} finally {
						requestList = [];
						isRefreshToken = false;
					}
				} else {
					if (!isRefreshToken) {
						// 添加到队列，等待刷新获取到新的令牌
						return new Promise(resolve => {
							requestList.push(() => {
								res.config.headers['Authorization'] = 'Bearer ' + getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
								resolve(service(res.config));
							});
						});
					} else {
						return handleAuthorized();
					}
				}
			} else if (code === 500) {
				Message({
					title: '提示',
					message: msg,
					type: 'error'
				});
				return res;
			} else if (code === 901) {
				Notification({
					title: '提示',
					type: 'error',
					duration: 0,
					dangerouslyUseHTMLString: true,
					message: '演示模式，无法进行写操作'
				});
				return Promise.reject(new Error(msg));
			} else if (code === 1002015003) {
				if (msg === '无效的刷新令牌') { // hard coding：忽略这个提示，直接登出
				} else {
					Message({
						title: '提示',
						message: msg,
						type: 'error'
					});
				}
				return res;
			} else if (code === 1010011002) { // 用于校验业务模块的某个字段是否重复，比如：配棉方案的版本号
				return res;
			} else if (code === 406) {
				return res;
			} else if (code === 504) { // 生产报工：审核时，检测是否有未下达计划的机台任务的异常处理
				MessageBox({
					title: '消息',
					message: `系统检测到有计划/开台缺失,是否立即处理 ？`,
					iconClass: 'el-icon-question',
					showCancelButton: true,
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					beforeClose: (action, instance, done) => {
						if (action === 'confirm') {
							route.push({
								name: 'SupplementaryPlanList'
							});
							done();
						} else {
							done();
						}
					}
				}).then(() => {}).catch(() => {});
			} else {
				Message({
					title: '提示',
					message: msg,
					type: 'error'
				});
				return res;
			}
		} else {
			return res;
		}
	}, error => {
		let { message } = error;
		if (message === 'Network Error') {
			message = '网络异常';
		} else if (message.includes('timeout')) {
			message = '系统接口请求超时';
		} else if (message.includes('Request failed with status code')) {
			message = '系统接口' + message.substr(message.length - 3) + '异常';
		}
		Notification({
			title: '提示',
			message: message,
			type: 'error',
			duration: 5 * 1000
		});
		return Promise.reject(error);
	}
);

import router from '../router';
import { getPlatformCustomerId } from './auth';
function handleAuthorized() {
	if (!isRelogin.show) {
		isRelogin.show = true;
		MessageBox.confirm('登录状态已过期，请重新登录！', '系统提示', {
				confirmButtonText: '去登录',
				cancelButtonText: '取消',
				type: 'warning'
			}
		).then(() => {
			isRelogin.show = false;
			store.dispatch('LogOut').then(() => {
				router.push({ path: '/login' });
			});
		}).catch(() => {
			isRelogin.show = false;
		});
	}
	return Promise.reject('无效的会话，或者会话已过期，请重新登录。');
}

// 注：axios get不支持通过body传参
export const getRequest = function(url, params) {
	return service.get(baseUrl + url, {
		params: params
	});
};

export const postRequest = function(url, data, params) {
	return service.post(baseUrl + url, data, { params: params });
};
export const putRequest = function(url, data, params) {
	return service.put(baseUrl + url, data, { params: params });
};
export const deleteRequest = function(url, params, data) {
	return service.delete(baseUrl + url, {
		params,
		data
	});
};

export default service;
